package com.koron.gateway.filter;

import com.auth0.jwt.interfaces.DecodedJWT;
import com.koron.bean.system.staff.Constant;
import com.koron.bean.util.JWTUtils;
import com.koron.bean.util.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Slf4j
@Component
@RefreshScope
@EnableConfigurationProperties({FilterIgnoreProperties.class})
public class AuthFilter implements GlobalFilter, Ordered {

    @Value("${isNeedLogin}")
    private Boolean isNeedLogin;

    @Value("${sso.redirectUrl}")
    private String redirectUrl;

    @Value("${sso.redirectEamLoginUrl:${sso.redirectUrl}}")
    private String redirectEamLoginUrl;

    @Value("${sso.casType:uma}")
    private String casType;

    //https://认证接口地址/idp/oauth2/authorize?redirect_uri=https://www.baidu.com&state=xxxx&client_id=xxxxx&response_type=code
    //https://iam-swdev.gdhwater.com:6443/idp/oauth2/authorize?redirect_uri=http://10.11.228.110:30001/eam-service-auth/auth/iamSsoLoginRedirect.htm&state=iam&client_id=EAM2&response_type=code

    @Value("${cas.redirectUrl:null}")
    private String zsjRedirectUrl;
    @Value("${sso.iamAuthorizeUrl:null}")
    private String authorizeUrl;

    @Autowired
    FilterIgnoreProperties ignoreProperties;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("Auth start");
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        MultiValueMap<String, String> queryParams = request.getQueryParams();
        HttpHeaders header = request.getHeaders();
        String token = header.getFirst(Constant.JWT_TOKEN);
        String dynamicDataSource = header.getFirst(Constant.DYNAMIC_DATA_SOURCE);
        //动态组织,领导,领导的组织
        String dynamicOrg = header.getFirst(Constant.DYNAMIC_AGENT_ORG);
        String dynamicLeader = header.getFirst(Constant.DYNAMIC_LEADER);
        String dynamicLeaderOrg = header.getFirst(Constant.DYNAMIC_LEADER_ORG);
        String mobile = header.getFirst(Constant.MOBILE);

        //其他系统回调时,无法携带请求头信息,可以将参数进行拼接在url后,统一处理
        //token
        if (StringUtils.isEmpty(token)) {
            token = queryParams.getFirst("token");
        }
        //动态数据源
        if (StringUtils.isEmpty(dynamicDataSource)) {
            dynamicDataSource = queryParams.getFirst("dynamicDataSource");
        }
        //动态组织
        if (StringUtils.isEmpty(dynamicOrg)) {
            dynamicOrg = queryParams.getFirst("dynamicOrg");
        }
        //动态领导
        if (StringUtils.isEmpty(dynamicLeader)) {
            dynamicLeader = queryParams.getFirst("dynamicLeader");
        }
        //动态leader组织
        if (StringUtils.isEmpty(dynamicLeaderOrg)) {
            dynamicLeaderOrg = queryParams.getFirst("dynamicLeaderOrg");
        }

        Map<String, String> cond = new HashMap<>();
        cond.put("token", token);
        cond.put("dynamicDataSource", dynamicDataSource);
        cond.put("dynamicOrg", dynamicOrg);
        cond.put("dynamicLeader", dynamicLeader);
        cond.put("dynamicLeaderOrg", dynamicLeaderOrg);

        String path = request.getPath().toString();
        // 移动端名单，有mobile这个header才会生效
        if (!StringUtils.isEmpty(mobile)) {
            // 在mobile名单里面
            List<String> mobilePaths = ignoreProperties.getMobilePaths();
            if (StringUtils.isEmpty(mobilePaths)) {
                return response.setComplete();
            }
            boolean isAllowMobile = false;
            for (String allowPath : mobilePaths) {
                if (path.contains(allowPath)) {
                    // 如果有，则进行转发
                    isAllowMobile = true;
                }
            }
            if (!isAllowMobile) {
                return response.setComplete();
            }
        }

        //白名单 不需要过滤的url
        List<String> allowPaths = ignoreProperties.getAllowPaths();
        if (CollectionUtils.isNotEmpty(allowPaths)) {
            for (String allowPath : allowPaths) {
                if (path.contains(allowPath)) {
                    return dealRequest(exchange, chain, cond);
                }
            }
        }

        if (isNeedLogin) {
            //判断是否跳转到oa 还是 eam自己做的登陆页面
            if (StringUtils.isEmpty(token)) {
                setSSORedirectHeader(request, response);
                return response.setComplete();
            } else {
                DecodedJWT verify = JWTUtils.verify(token);
                if (verify == null) {
                    log.error("invalid token");
                    setSSORedirectHeader(request, response);
                    return response.setComplete();
                } else {
                    String account = verify.getClaim(Constant.ACCOUNT).asString();
                    String userStr = (String) RedisUtils.hget(Constant.EAM_SERVICE_AUTH, account);
                    if (StringUtils.isEmpty(userStr)){
                        //说明redis中没有该账号信息
                        setSSORedirectHeader(request, response);
                        return response.setComplete();
                    }
                }
            }
        }

        return dealRequest(exchange, chain, cond);

    }

    private Mono<Void> dealRequest(ServerWebExchange exchange, GatewayFilterChain chain, Map<String, String> params) {

        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        String token = params.get("token");
        String dynamicDataSource = params.get("dynamicDataSource");
        String dynamicOrg = params.get("dynamicOrg");
        String dynamicLeader = params.get("dynamicLeader");
        String dynamicLeaderOrg = params.get("dynamicLeaderOrg");

        //暂时先补上默认
        log.info("当前数据源：{}", dynamicDataSource);




if (StringUtils.isEmpty(dynamicDataSource)) {
            dynamicDataSource = "water_02";
        }




        // 将用户信息存放在请求header中传递给下游业务
        ServerHttpRequest.Builder mutate = request.mutate();
        mutate.header(Constant.JWT_TOKEN, token);
        mutate.header(Constant.DYNAMIC_DATA_SOURCE, dynamicDataSource);
        mutate.header(Constant.DYNAMIC_AGENT_ORG, dynamicOrg);
        mutate.header(Constant.DYNAMIC_LEADER, dynamicLeader);
        mutate.header(Constant.DYNAMIC_LEADER_ORG, dynamicLeaderOrg);
        ServerHttpRequest buildReuqest = mutate.build();

        // 如果响应中需要放数据，也可以放在response的header中
        response.setStatusCode(HttpStatus.OK);
        return chain.filter(exchange.mutate()
                .request(buildReuqest)
                .response(response)
                .build());

    }

    private void setSSORedirectHeader(ServerHttpRequest request, ServerHttpResponse response) {
        HttpHeaders responseHeaders = response.getHeaders();
        response.setStatusCode(HttpStatus.FOUND);

        HttpHeaders requestHeaders = request.getHeaders();
        String outOrg = requestHeaders.getFirst(Constant.OUT_ORG);

        if (!StringUtils.isEmpty(outOrg) && "1".equals(outOrg)) {
            //外单位
            //重定向到访问地址
            log.info("eam 重定向到外单位登录URL: {}", redirectEamLoginUrl);
            //can not use 302 ajax
            responseHeaders.set("redirectUrl", redirectEamLoginUrl);
        } else {
            if (Constant.CasType.IAM.equals(casType)) {
                //重定向到访问地址
                log.info("eam 重定向到内单位登录URL: {}", authorizeUrl);
                //can not use 302 ajax
                responseHeaders.set("redirectUrl", authorizeUrl);
                return;
            }else if (Constant.CasType.ZSJ.equals(casType)){
                //重定向到访问地址
                log.info("eam 重定向到内单位登录URL: {}", zsjRedirectUrl);
                //can not use 302 ajax
                responseHeaders.set("redirectUrl", zsjRedirectUrl);
            }
            else{
            //重定向到访问地址
            log.info("eam 重定向到内单位登录URL: {}", redirectUrl);
            }
            //can not use 302 ajax
            responseHeaders.set("redirectUrl", redirectUrl);
        }
    }

    @Override
    public int getOrder() {
        return 0;
    }
}


